package mymongo

import (
    "context"
    "fmt"
    "io/ioutil"
    "time"
    "sync"
    "encoding/json"
    "path/filepath"
    "mygo/mystruct"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
    "go.mongodb.org/mongo-driver/bson/primitive"
)


type Collections struct {
	*mongo.Collection
}

type Myclient struct {
	Client 		*mongo.Client
	ApiCur      Collections
	UserCur     Collections
	DanmakuCur  Collections
	Database	*mongo.Database
	DataCur     map[string]Curs
}

type MongoDBConfig struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Server   string `json:"server"`
	Port     string `json:"port"`
}

type Curs struct {
	Cur 	*mongo.Collection
	Body 	*mystruct.ModelItem
}


type MongoDocument struct {
    ID         primitive.ObjectID `bson:"_id"`
    Data       primitive.M        `bson:"data"`
    AppendTime primitive.DateTime `bson:"appendtime,omitempty"` // 可选字段
}

var clientsMu sync.Mutex

var MyMonDB Myclient

var MYUSER_CACHE = make(map[string]*mystruct.Musercode)



/* =================================================================================
   初始化
*/
// 数据库初始化
func Myinit(mpath string) error {
	mongopath := filepath.Join(mpath, "mongodb.json")
	var mogurl string
	if mystruct.Exists(mongopath) && mystruct.IsFile(mongopath) {
		fileContent, err := ioutil.ReadFile(mongopath)
		if err != nil {
			return fmt.Errorf("无法读取配置文件: %w", err)
		}
		var result MongoDBConfig
		json.Unmarshal(fileContent, &result)
		mogurl = fmt.Sprintf("mongodb://%s:%s@%s:%s", result.Username, result.Password, result.Server, result.Port)
	}else{
		mogurl = "mongodb://localhost:27017"
	}
	mongurl := options.Client().ApplyURI(mogurl).SetMaxPoolSize(200).SetMinPoolSize(15)
	client, err := mongo.Connect(context.TODO(), mongurl)
	if err != nil || client.Ping(context.TODO(), readpref.Primary()) != nil {
		return err
	}
	MyMonDB = Myclient{
		Client: client, 
		ApiCur: Collections{client.Database("MyMonDB_API").Collection("api")},
		UserCur: Collections{client.Database("MyMonDB_API").Collection("user")},
		DanmakuCur: Collections{client.Database("MyMonDB_API").Collection("danmaku")},
		Database: client.Database("MyMonDB_DATA"),
		DataCur: make(map[string]Curs),
	}
	return nil
}
// 初始化创建索引
func initializeIndexes(MyMonDB Myclient) error {
	_, all_data := MyMonDB.ApiCur.See()
	for _, body := range all_data {
		collection := MyMonDB.Database.Collection(body.Api)
		var indexes []mongo.IndexModel
		for _, key := range body.Data {
			indexes = append(indexes, mongo.IndexModel{
				Keys: bson.D{{Key: "data." + key.Value, Value: 1}},
				Options: options.Index().SetName(fmt.Sprintf("data_%s_idx", key.Value)),
			})
		}
		if len(indexes) == 0 {
			continue
		}
		collection.Indexes().CreateMany(context.TODO(), indexes)
	}
    return nil
}
// 定时检查登录时效
func NewTickerFor(structtoken *mystruct.Mytoken) {
    ticker := time.NewTicker(120 * time.Second)
    for _ = range ticker.C {
        clientsMu.Lock()
        stop_time := time.Now()
        for key, value := range MYUSER_CACHE {
        	diffSeconds := int64(stop_time.Sub(value.Time).Seconds())
        	if diffSeconds > structtoken.Sleeptime {
        		delete(MYUSER_CACHE, key)
        	}
        }
        clientsMu.Unlock()
    }
}

type StringRowPool struct {
    pool sync.Pool
}

func newStringRowPool(size int) *StringRowPool {
    return &StringRowPool{
        pool: sync.Pool{
            New: func() interface{} {
                return make([]string, size)
            },
        },
    }
}

func (p *StringRowPool) Get() []string {
	m := p.pool.Get().([]string)
	for i := range m {
        m[i] = ""
    }
    return m
}

func (p *StringRowPool) Put(row []string) {
    // 重置但不释放内存
    p.pool.Put(row)
}


type PrimitiveRowPool struct {
	pool sync.Pool
}

func newPrimitiveRowPool() *PrimitiveRowPool {
    return &PrimitiveRowPool{
        pool: sync.Pool{
            New: func() interface{} {
                return make(primitive.M) // 预分配容量
            },
        },
    }
}

func (p *PrimitiveRowPool) Get() primitive.M {
    m := p.pool.Get().(primitive.M)
    // 获取后立即清空
    for k := range m {
        delete(m, k)
    }
    return m
}

func (p *PrimitiveRowPool) Put(row primitive.M) {
    // 重置但不释放内存
    p.pool.Put(row)
}

